import static org.junit.Assert.*;

import java.util.ArrayList;

import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.zanateh.wargame.game.*;
import org.zanateh.wargame.game.events.IMoveRejectedEventListener;
import org.zanateh.wargame.game.events.MoveRejectedEvent;
import org.zanateh.wargame.game.hexagon.Hexagon;
import org.zanateh.wargame.game.hexagon.HexagonFactory;
import org.zanateh.wargame.game.hexagon.HexField.NotInitializedException;
import org.zanateh.wargame.game.moveevaluators.IMoveEvaluator;
import org.zanateh.wargame.game.moveevaluators.MoveEvaluator;
import org.zanateh.wargame.game.moveevaluators.NoOtherSamePlayerOccupantsMoveEvaluator;
import org.zanateh.wargame.game.piece.Piece;


public class PieceTest {

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testPieceCreation() {
		Piece piece = new Piece();
		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.setHex(hex);
		Assert.assertEquals(hex, piece.getHex());
	}
	
	@Test
	public void testMove() {
		Piece piece = new Piece();
		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.setHex(hex);
		Hexagon newHex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.moveTo(newHex);
		Assert.assertEquals(newHex, piece.getHex());
	}
	
	class TestSuccessMoveEvaluator extends MoveEvaluator
	{

		@Override
		public boolean allowMove(Hexagon pHex) {
			return true;
		}

		@Override
		public String getRejectedMessage() {
			// TODO Auto-generated method stub
			return null;
		}
		
	}
	
	@Test
	public void testMoveWithEvaluatorSuccessful()
	{
		Piece piece = new Piece();
		IMoveEvaluator evaluator = new TestSuccessMoveEvaluator();
		piece.addMoveEvaluator(evaluator);
		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.setHex(hex);
		Hexagon newHex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.moveTo(newHex);
		Assert.assertEquals(newHex, piece.getHex());
	}
	
	class TestFailMoveEvaluator extends MoveEvaluator
	{
		public final static String failMessage = "FAILMESSAGE";
		
		@Override
		public boolean allowMove(Hexagon pHex) {
			return false;
		}

		@Override
		public String getRejectedMessage() {
			// TODO Auto-generated method stub
			return failMessage;
		}
		
	}
	
	@Test
	public void testMoveWithEvaluatorFailed()
	{
		Piece piece = new Piece();
		IMoveEvaluator evaluator = new TestFailMoveEvaluator();
		piece.addMoveEvaluator(evaluator);
		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.setHex(hex);
		Hexagon newHex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.moveTo(newHex);
		Assert.assertEquals(hex, piece.getHex());
	}

	class TestMoveRejectedListener implements IMoveRejectedEventListener
	{
		public String moveRejectedReason = null;
		public Object moveRejectedObject = null;
		
		@Override
		public void moveRejected(MoveRejectedEvent event) {
			moveRejectedObject = event.getSource();
			moveRejectedReason = event.getRejectedMessage();
		}
		
	}
	
	@Test
	public void testMoveRejectedEvent()
	{
		Piece piece = new Piece();
		IMoveEvaluator evaluator = new TestFailMoveEvaluator();
		piece.addMoveEvaluator(evaluator);
		
		TestMoveRejectedListener listener = new TestMoveRejectedListener();
		piece.addMoveRejectedListener(listener);

		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.setHex(hex);
		Hexagon newHex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.moveTo(newHex);
		
		Assert.assertEquals(TestFailMoveEvaluator.failMessage, listener.moveRejectedReason);
		Assert.assertSame(piece, listener.moveRejectedObject);
		
	}
	
	@Test
	public void testPieceOccupancy()
	{
		Piece piece = new Piece();
		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.setHex(hex);
		Assert.assertTrue(hex.getOccupants().contains(piece));
		
		Hexagon newHex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);
		piece.moveTo(newHex);
		Assert.assertFalse(hex.getOccupants().contains(piece));
		Assert.assertTrue(newHex.getOccupants().contains(piece));
	}
	
	@Test
	public void testPieceEntryIntoOccupiedHex()
	{
		Piece piece = new Piece();
		IMoveEvaluator evaluator = new NoOtherSamePlayerOccupantsMoveEvaluator();
		piece.addMoveEvaluator(evaluator);
		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);

		TestMoveRejectedListener listener = new TestMoveRejectedListener();
		piece.addMoveRejectedListener(listener);
		
		piece.setHex(hex);
		Assert.assertNull(listener.moveRejectedObject);
		
		Piece piece2 = new Piece();
		piece2.addMoveRejectedListener(listener);
		piece2.moveTo(hex);
		
		Assert.assertSame(piece2, listener.moveRejectedObject);
	}
	
	@Test
	public void testPieceEntryIntoOccupiedHexSameOwnership() {
		Player player = new Player("P1");
		Piece piece = new Piece(player);
		IMoveEvaluator evaluator = new NoOtherSamePlayerOccupantsMoveEvaluator();
		piece.addMoveEvaluator(evaluator);
		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);

		TestMoveRejectedListener listener = new TestMoveRejectedListener();
		piece.addMoveRejectedListener(listener);
		
		piece.setHex(hex);
		Assert.assertNull(listener.moveRejectedObject);
		
		Piece piece2 = new Piece(player);
		piece2.addMoveRejectedListener(listener);
		piece2.moveTo(hex);
		
		Assert.assertSame(piece2, listener.moveRejectedObject);	
	}
	
	@Test
	public void testPieceEntryIntoOccupiedHexDifferentOwnership() {
		Player player1 = new Player("P1");
		Player player2 = new Player("P2");
		Piece piece = new Piece(player1);
		IMoveEvaluator evaluator = new NoOtherSamePlayerOccupantsMoveEvaluator();
		piece.addMoveEvaluator(evaluator);
		Hexagon hex = HexagonFactory.createHexagon(HexagonFactory.HexagonType.TEST);

		TestMoveRejectedListener listener = new TestMoveRejectedListener();
		piece.addMoveRejectedListener(listener);
		
		piece.setHex(hex);
		Assert.assertNull(listener.moveRejectedObject);
		
		Piece piece2 = new Piece(player2);
		piece2.addMoveRejectedListener(listener);
		piece2.moveTo(hex);
		
		Assert.assertNull(listener.moveRejectedObject);
		Assert.assertSame(piece2.getHex(), piece.getHex());
	}
	
}
